#include "looper.h"

#include <map>
#include <list>
#include <time.h>
#include <iostream>

namespace looper
{	
	class Message
	{
	public:
		Message() = default;
	
		Message(Handler* handler, RunnableSP runnableSP, uint64_t expireMillis)
		{
			mHandler = handler;
			mRunnableSP = runnableSP;
			mExpireMillis = expireMillis;
		}
	
	public:
		Handler* 	mHandler{nullptr};
		RunnableSP	mRunnableSP;
		uint64_t 	mExpireMillis;
	};
	
	static std::map<Looper*, std::list<Message>> sLooperToMessagesMap;
	static std::mutex sMapMutex;
	
	// 线程回调函数
	static void prvLoop(Looper* looper)
	{
		looper->loop();
	}
	
	// 系统运行时间
	static uint64_t prvGetUpMillis()
	{
		timespec now;
		clock_gettime(CLOCK_MONOTONIC, &now);
		return now.tv_sec*1000LL + now.tv_nsec/1000000LL;
	}
	
	Looper::Looper()
	{
		std::lock_guard<std::mutex> lock(sMapMutex);
		sLooperToMessagesMap.emplace(this, std::list<Message>());
		mThread = std::thread(prvLoop, this);
	}
	
	Looper::~Looper()
	{
		// 尽快移除,以免Handler继续可以发送
		{
			std::lock_guard<std::mutex> lock(sMapMutex);
			sLooperToMessagesMap.erase(this);
		}
		while (mIsLoop)
		{
			std::unique_lock<std::mutex> lock(mMutex);
			mCondVar.notify_one();
		}
		mThread.join();
	}
	
	void Looper::postDelayed(Handler* handler, RunnableSP runnableSP, uint64_t delayMillis)
	{
		uint64_t expireMillis = prvGetUpMillis() + delayMillis;
		
		// 寻找位置进行插入
		std::list<Message>& messageList = sLooperToMessagesMap[this];			
		auto it = messageList.begin();
		bool needNotify = true;
		while (it != messageList.end() && expireMillis >= it->mExpireMillis)
		{
			it++;
			needNotify = false;
		}
		messageList.insert(it, Message(handler, runnableSP, expireMillis));
		
		// 唤醒
		if (needNotify)
		{
			std::unique_lock<std::mutex> lock(mMutex);
			mCondVar.notify_one();
		}
	}
	
	void Looper::removeCallbacks(Handler* handler, RunnableSP runnableSP)
	{
		bool needNotify = false;
		std::list<Message>& messageList = sLooperToMessagesMap[this];		
		for (auto it = messageList.begin(); it != messageList.end(); it++)
		{
			if (it->mHandler == handler && (!runnableSP || it->mRunnableSP == runnableSP))
			{
				if (it == messageList.begin())
				{
					needNotify = true;
				}
				it = messageList.erase(it);				
			}
		}		
		
		// 唤醒
		if (needNotify)
		{
			std::unique_lock<std::mutex> lock(mMutex);
			mCondVar.notify_one();
		}
		
	}
	
	void Looper::loop()
	{		
		while (true)
		{	
			bool emptyList = false;
			long waitMillis = 0;
			Message msg;
			{
				std::lock_guard<std::mutex> lock(sMapMutex);
				auto it = sLooperToMessagesMap.find(this);
				// Looper将要退出
				if (it == sLooperToMessagesMap.end())
				{
					break;
				}
				std::list<Message>& messageList = it->second;				
				
				// 长久等待				
				if (messageList.empty())
				{
					emptyList = true;
				}
				else
				{					
					msg = messageList.front();
					uint64_t upMillis = prvGetUpMillis();
					if (msg.mExpireMillis > upMillis)
					{
						waitMillis = (long)(msg.mExpireMillis - upMillis);
					}
					else
					{
						// 移除
						messageList.pop_front();
					}
				}
			}
			
			// 空列表
			if (emptyList)
			{
				std::unique_lock<std::mutex> lock(mMutex);
				mCondVar.wait(lock);
				continue;
			}
			
			// 时间还没到
			if (waitMillis)
			{
				std::unique_lock<std::mutex> lock(mMutex);
				mCondVar.wait_for(lock, std::chrono::milliseconds(waitMillis));
				continue;
			}
			
			// 运行
			msg.mRunnableSP->run();
		}		
		mIsLoop = false;
	}
	
} // namespace looper



namespace looper
{	
	Handler::Handler(Looper* looper) : mLooper{looper} {}
		
	// Looper中此Handler发出的还没被执行的IRunnable会被清除
	Handler::~Handler()
	{
		removeCallbacks(RunnableSP());
	}
	
	// (如果Looper已经销毁,此post失效)
	void Handler::post(RunnableSP runnableSP)
	{
		postDelayed(runnableSP, 0);
	}
	
	// (如果Looper已经销毁,此post失效)
	void Handler::postDelayed(RunnableSP runnableSP, uint64_t delayMillis)
	{
		if (!runnableSP)
		{
			return;
		}
		
		std::lock_guard<std::mutex> lock(sMapMutex);
		if (sLooperToMessagesMap.find(mLooper) != sLooperToMessagesMap.end())
		{
			mLooper->postDelayed(this, runnableSP, delayMillis);
		}
	}
	
	// 清除所有此Handler发出去的还没被执行的IRunnable
	// r == nullptr, 移除所有该Handler发处的IRunnable
	void Handler::removeCallbacks(RunnableSP runnableSP)
	{
		std::lock_guard<std::mutex> lock(sMapMutex);
		if (sLooperToMessagesMap.find(mLooper) != sLooperToMessagesMap.end())
		{
			mLooper->removeCallbacks(this, runnableSP);
		}
	}

} // namespace looper
